package org.xxpay.pay.task;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.xxpay.apibase.service.IDCAlizftpayChannelService;
import org.xxpay.apibase.service.IDCNotifyService;
import org.xxpay.apibase.service.IDCPaymentService;
import org.xxpay.apibase.vo.ApiPayOrder;
import org.xxpay.core.common.constant.MchConstant;
import org.xxpay.core.common.constant.PayConstant;
import org.xxpay.core.common.constant.RetEnum;
import org.xxpay.core.common.domain.api.AbstractRes;
import org.xxpay.core.common.domain.api.ApiBuilder;
import org.xxpay.core.common.domain.api.PayQueryRes;
import org.xxpay.core.common.domain.api.PayRes;
import org.xxpay.core.common.domain.api.msg.QueryRetMsg;
import org.xxpay.core.common.exception.ServiceException;
import org.xxpay.core.common.util.DateUtils;
import org.xxpay.core.common.util.MyLog;
import org.xxpay.core.common.vo.DBApplicationConfig;
import org.xxpay.core.entity.PayInterface;
import org.xxpay.core.entity.PayOrder;
import org.xxpay.core.entity.PayPassageAccount;
import org.xxpay.pay.channel.PayNotifyInterface;
import org.xxpay.pay.channel.PaymentInterface;
import org.xxpay.pay.mq.BaseNotify4AlizftpayTradeSettleConfirm;
import org.xxpay.pay.mq.BaseNotify4CashColl;
import org.xxpay.pay.mq.BaseNotify4MchPay;
import org.xxpay.pay.mq.queue.MqQueue4Statistics;
import org.xxpay.pay.service.CommonService;
import org.xxpay.pay.service.LocalDynamicChannelService;
import org.xxpay.pay.util.SpringUtil;
import org.xxpay.pay.websocket.server.WsPayOrderServer;

import java.util.Date;
import java.util.List;

/**
 * @author: dingzhiwei
 * @date: 18/11/05
 * @description: 支付补单任务
 */
@Component
public class ReissuePayScheduled extends ReissuceBase {

    @Autowired
    private CommonService commonService;

    private static final MyLog _log = MyLog.getLog(ReissuePayScheduled.class);

    @Autowired
    public BaseNotify4MchPay baseNotify4MchPay;

    @Autowired
    public BaseNotify4CashColl baseNotify4CashColl;

    @Autowired
    private MqQueue4Statistics mqQueue4Statistics;

    @Autowired private LocalDynamicChannelService localDynamicChannelService;

    @Autowired private IDCAlizftpayChannelService dcAlizftpayChannelService;

    /**
     * 支付订单批量补单任务
     */
    @Scheduled(cron="0 0/1 * * * ?") //每分钟执行一次
    public void payReissueTask() {
        String logPrefix = "【支付补单】";
        // 支付补单开关
        DBApplicationConfig dbConfig = commonService.sysConfigService.getDBApplicationConfig();
        if(!isExcuteReissueTask(dbConfig.getTaskReissuePaySwitch(), dbConfig.getTaskReissuePayIp())) {
            _log.info("{}当前机器不执行支付补单任务", logPrefix);
            return;
        }
        int pageIndex = 1;
        int limit = 100;
        PayOrder queryPayOrder = new PayOrder();
        queryPayOrder.setStatus(PayConstant.PAY_STATUS_PAYING);   // 支付中
        // 查询需要处理的订单
        Date createTimeStart = new Date(System.currentTimeMillis() - 2 * 60 * 60 * 1000);  // 2小时
        Date createTimeEnd = new Date(System.currentTimeMillis() - 1 * 60 * 1000);          // 1分钟
        boolean flag = true;
        _log.info("{}开始查询需要处理的支付订单,查询订单{}<=创建时间<={}", logPrefix, DateUtils.getTimeStr(createTimeStart, "yyyy-MM-dd HH:mm:ss"), DateUtils.getTimeStr(createTimeEnd, "yyyy-MM-dd HH:mm:ss"));
        // 循环查询所有
        while (flag) {
            List<PayOrder> payOrderList = commonService.payOrderService.select((pageIndex - 1) * limit, limit, queryPayOrder, createTimeStart, createTimeEnd);
            _log.info("{}查询需要处理的支付订单,共:{}条", logPrefix, payOrderList == null ? 0 : payOrderList.size());
            for(PayOrder payOrder : payOrderList) {
                long startTime = System.currentTimeMillis();
                String payOrderId = payOrder.getPayOrderId();
                _log.info("{}开始处理payOrderId={}", logPrefix, payOrderId);
                // 渠道类型
                String channelType = payOrder.getChannelType();
                QueryRetMsg retObj;
                try{

                    Object instance = localDynamicChannelService.getPaymentInterface(channelType);  //获取通道对象示例

                    if(instance == null){
                        _log.warn("{}不支持的支付渠道, 实例化失败！ 停止处理.payOrderId={},channelType={}", logPrefix, payOrderId, channelType);
                        continue;
                    }

                    if(instance instanceof PaymentInterface) {
                        PaymentInterface paymentInterface = (PaymentInterface) instance;
                        retObj = paymentInterface.query(payOrder);
                    }else{

                        IDCPaymentService paymentInterface = (IDCPaymentService)instance;

                        //查询必要参数
                        ApiPayOrder apiPayOrder = new ApiPayOrder();
                        BeanUtils.copyProperties(payOrder, apiPayOrder);  //bean copy

                        retObj = convertRes( paymentInterface.query(apiPayOrder, getPayParamJSON(payOrder.getPassageAccountId())) );

                    }


                }catch (BeansException e) {
                    _log.warn("{}不支持的支付渠道,停止处理.payOrderId={},channelType={}", logPrefix, payOrderId, channelType);
                    continue;
                }catch (Exception e) {
                    _log.warn("{}查询上游订单异常", logPrefix, payOrderId);
                    _log.error(e, "");
                    continue;
                }
                if(retObj == null) {
                    _log.warn("{}查询上游返回空,停止处理.payOrderId={},channelType={}", logPrefix, payOrderId, channelType);
                    continue;
                }
                // 查询成功
                if(retObj.getChannelState() == QueryRetMsg.ChannelState.CONFIRM_SUCCESS) {
                    String channelOrderNo = retObj.getChannelOrderId();
                    int updatePayOrderRows = commonService.payOrderService.updateStatus4Success(payOrderId, channelOrderNo);
                    _log.info("{}更新支付订单状态为成功({}),payOrderId={},返回结果:{}", logPrefix, PayConstant.PAY_STATUS_SUCCESS, payOrderId, updatePayOrderRows);
                    if (updatePayOrderRows == 1) {
                        payOrder.setStatus(PayConstant.TRANS_STATUS_SUCCESS);
                        // 通知业务系统
                        payOrder = commonService.payOrderService.findByPayOrderId(payOrderId);
                        baseNotify4MchPay.doNotify(payOrder, true);

                        //推送ws消息到浏览器
                        wsPayOrderServer.sendMsgByOrderId(payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS, payOrder.getReturnUrl());

                        //资金归集
                        if("alipay_qr_pc".equals(payOrder.getChannelId()) || "alipay_qr_h5".equals(payOrder.getChannelId())){
                            baseNotify4CashColl.doNotify(payOrderId);
                        }

                        //如果为直付通接口， 需要调用结算接口
                        if( PayConstant.CHANNEL_NAME_ALIZFTPAY.equals( payOrder.getChannelType())){
                            dcAlizftpayChannelService.tradeSettleConfirm(payOrder.getChannelOrderNo(), payOrderId);
                        }

                    }
                }
                _log.info("{}处理完毕payOrderId={}.耗时:{} ms", logPrefix, payOrderId, System.currentTimeMillis() - startTime);
            }
            pageIndex++;
            if(CollectionUtils.isEmpty(payOrderList) || payOrderList.size() < limit) {
                flag = false;
            }
        }
        _log.info("{}本次查询处理完成,", logPrefix);
    }


    private JSONObject getPayParamJSON(Integer passageAccountId) {
        String payParam = "";
        PayPassageAccount payPassageAccount = commonService.payPassageAccountService.findById(passageAccountId);

        if(payPassageAccount == null) throw new ServiceException(RetEnum.RET_MGR_PAY_PASSAGE_ACCOUNT_NOT_EXIST);

        payParam = payPassageAccount.getParam();
        if(StringUtils.isBlank(payParam)) throw new ServiceException(RetEnum.RET_MGR_PAY_PASSAGE_ACCOUNT_NOT_EXIST); //仍然为空，说明配置有误

        return JSONObject.parseObject(payParam);
    }

    /** 转换对象 **/
    private QueryRetMsg convertRes(org.xxpay.apibase.vo.api.msg.QueryRetMsg retMsg){
        return JSONObject.parseObject(JSON.toJSONString(retMsg), QueryRetMsg.class);
    }

}
